extends layout

block append style
  link(rel="stylesheet", href="/docs/css/inlinecpc.css")
  script(type="text/javascript" src="/docs/js/native.js")

block content
  :markdown
    # Using GeoJSON

    <script>
      _native.init("CK7DT53U",{
        targetClass: 'native-inline'
      });
    </script>

    <div class="native-inline">
      <a href="#native_link#"><span class="sponsor">Sponsor</span> #native_company# — #native_desc#</a>
    </div>

    [GeoJSON](http://geojson.org/) is a format for storing geographic points and
    polygons. [MongoDB has excellent support for geospatial queries](http://thecodebarbarian.com/80-20-guide-to-mongodb-geospatial-queries)
    on GeoJSON objects. Let's take a look at how you can use Mongoose to store
    and query GeoJSON objects.

    <h2 id="points">Point Schema</h2>

    The most simple structure in GeoJSON is a point. Below is an example point
    representing the approximate location of [San Francisco](https://www.google.com/maps/@37.7,-122.5,9z).
    Note that longitude comes first in a GeoJSON coordinate array, **not** latitude.

    ```
    {
      "type" : "Point",
      "coordinates" : [
        -122.5,
        37.7
      ]
    }
    ```

    Below is an example of a Mongoose schema where `location` is a point.

    ```javascript
    const citySchema = new mongoose.Schema({
      name: String,
      location: {
        type: {
          type: String, // Don't do `{ location: { type: String } }`
          enum: ['Point'], // 'location.type' must be 'Point'
          required: true
        },
        coordinates: {
          type: [Number],
          required: true
        }
      }
    });
    ```

    Using [subdocuments](/docs/subdocs.html), you can define a common `pointSchema` and reuse it everywhere you want to store a GeoJSON point.

    ```javascript
    const pointSchema = new mongoose.Schema({
      type: {
        type: String,
        enum: ['Point'],
        required: true
      },
      coordinates: {
        type: [Number],
        required: true
      }
    });

    const citySchema = new mongoose.Schema({
      name: String,
      location: {
        type: pointSchema,
        required: true
      }
    });
    ```

    <h2 id="polygons">Polygon Schema</h2>

    GeoJSON polygons let you define an arbitrary shape on a map. For example,
    the below polygon is a GeoJSON rectangle that approximates the border
    of the state of Colorado.

    ```
    {
      "type": "Polygon",
      "coordinates": [[
        [-109, 41],
        [-102, 41],
        [-102, 37],
        [-109, 37],
        [-109, 41]
      ]]
    }
    ```

    Polygons are tricky because they use triple nested arrays. Below is
    how you create a Mongoose schema where `coordinates` is a triple nested
    array of numbers.

    ```javascript
    const polygonSchema = new mongoose.Schema({
      type: {
        type: String,
        enum: ['Polygon'],
        required: true
      },
      coordinates: {
        type: [[[Number]]], // Array of arrays of arrays of numbers
        required: true
      }
    });

    const citySchema = new mongoose.Schema({
      name: String,
      location: polygonSchema
    });
    ```

    <h2 id="querying">Geospatial Queries with Mongoose</h2>

    Mongoose queries support the same [geospatial query operators](http://thecodebarbarian.com/80-20-guide-to-mongodb-geospatial-queries)
    that the MongoDB driver does. For example, the below script saves a
    `city` document those `location` property is a GeoJSON point representing
    the city of Denver, Colorado. It then queries for all documents within
    a polygon representing the state of Colorado using
    [the MongoDB `$geoWithin` operator](https://docs.mongodb.com/manual/reference/operator/query/geoWithin/).

    <img src="https://i.imgur.com/i32pWnC.png">

    ```javascript
    [require:geojson.*driver query]
    ```

    Mongoose also has a [`within()` helper](/docs/api.html#query_Query-within)
    that's a shorthand for `$geoWithin`.

    ```javascript
    [require:geojson.*within helper]
    ```
